
from rest_framework import serializers
from goods.models import SKU,SKUSpecification,GoodsCategory,SPU,\
    SPUSpecification,SpecificationOption

# 选项序列化器
class OptModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = SpecificationOption
        fields = [
            'id',
            'value'
        ]

# 规格序列化器
class SpecModelSerializer(serializers.ModelSerializer):
    spu = serializers.StringRelatedField()

    # 关联的从表对象 --> 当前规格关联的多个选项SpecificationOption对象
    options = OptModelSerializer(many=True)

    class Meta:
        model = SPUSpecification
        fields = [
            'id',
            'name',
            'spu',
            'spu_id',
            'options'
        ]

# SPU序列化器
class SPUSimpleModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = SPU
        fields = [
            'id',
            'name'
        ]

# 分类序列化器
class GoodsCateModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = GoodsCategory
        fields = [
            'id',
            'name'
        ]


class SKUSpecOptModelSerializer(serializers.ModelSerializer):
    spec_id = serializers.IntegerField()
    option_id = serializers.IntegerField()

    class Meta:
        model = SKUSpecification
        fields = [
            'spec_id', # 隐藏情况：主键隐藏字段，和，外键隐藏字段默认映射的时候read_only=True只参与序列化
            'option_id'
        ]

# SKU序列化器
class SKUModelSerializer(serializers.ModelSerializer):
    # 1、外键关联对象字段序列化结果为名称，类型重写定义为StringRelatedField
    # 2、外键关联对象的主键隐藏字段不会自动映射，所以我们需要自定义
    spu = serializers.StringRelatedField()
    spu_id = serializers.IntegerField()
    category = serializers.StringRelatedField()
    category_id = serializers.IntegerField()

    # 3、关联从表隐藏字段 --> 多个SKUSpecification模型类对象(由主到从嵌套序列化)
    specs = SKUSpecOptModelSerializer(many=True)

    class Meta:
        model = SKU
        # __all__表示显示定义字段和主键隐藏字段会自动映射
        fields = '__all__'

    def create(self, validated_data):
        # 因为模型类序列化器默认的create方法，无法根据specs字段新建中间表数据
        # 1、把specs字段从有效数据中pop出来
        # specs = [{spec_id: "4", option_id: 8}, {spec_id: "5", option_id: 11}]
        specs = validated_data.pop('specs')

        from django.db import transaction

        with transaction.atomic():
            save_id = transaction.savepoint()

            try:
                # 2、新建sku对象
                sku = SKU.objects.create(**validated_data)
                # 3、新建中间表数据SKUSpecification
                for spec in specs:
                    # spec = {'spec_id': 4, 'option_id': 8}
                    spec['sku_id'] = sku.id # spec = {'spec_id': 4, 'option_id': 8, 'sku_id': 17}
                    SKUSpecification.objects.create(**spec)
            except Exception as e:
                # 说明sql执行有失败，表明数据一致性被破坏，回滚
                transaction.savepoint_rollback(save_id)

            transaction.savepoint_commit(save_id)

        return sku


    def update(self, instance, validated_data):
        # 因为模型类序列化器默认的update方法，无法根据specs字段来更新中间表数据
        # 1、从有效数据中剔除specs
        # specs = [{spec_id: "4", option_id: 10}, {spec_id: "5", option_id: 12}]
        specs = validated_data.pop('specs')

        from django.db import transaction
        with transaction.atomic():
            save_id = transaction.savepoint()

            try:
                # 2、更新sku数据
                sku = super().update(instance, validated_data)
                # 3、根据新的规格选项插入中间表数据SKUSpecification
                # 3.1、清除原有的当前sku的规格和选项
                SKUSpecification.objects.filter(sku=sku).delete()
                # 3.2、根据新的规格选项插入中间表数据
                for spec in specs:
                    # spec = {spec_id: "4", option_id: 10}
                    spec['sku_id'] = sku.id
                    SKUSpecification.objects.create(**spec)
            except Exception as e:
                transaction.savepoint_rollback(save_id)

            transaction.savepoint_commit(save_id)

        return sku








